#include "spk_camera.h"
#include "spk_packet.h"

#define LOG_TAG "spk_packet"
#define LOG_LVL LOG_LVL_DBG
#include "spk_ulog.h"

const char *str_type(u8 type)
{
    switch (type)
    {
    case CMD_DEVICE_SCAN:
        return "device scan cmd";
    case CMD_DEVICE_INFO:
        return "device info packet";
    case CMD_DEVICE_ONLINE:
        return "device online msg";
    case CMD_DEVICE_CTRL:
        return "device ctrl cmd";
    case CMD_DEVICE_CTRL_ACK:
        return "device ctrl cmd ack";
    case CMD_DEVICE_REFRESH:
        return "device ctrl refresh cmd";
    case CMD_DEVICE_REFRESH_ACK:
        return "device ctrl refresh cmd ack";
    case CMD_DEVICE_REBOOT:
        return "device reboot cmd";
    case CMD_DEVICE_REBOOT_ACK:
        return "device reboot cmd ack";
    case CMD_DEVICE_CLOSE:
        return "device close msg";
    default:
        return "unknown";
    }
}

int spk_packet::send_packet(u8 type, void *data, u16 len, void *param)
{
    u8 buf[SPK_PACKET_MAX_LEN + 6];

    buf[0] = SPK_PACKET_HEADER; /*包头*/
    buf[1] = type;              /*类型*/
    buf[2] = len & 0xFF;        /*长度*/
    buf[3] = (len >> 8) & 0xFF;

    if (len)
        memcpy(buf + 4, data, len);

    /*计算校验和*/
    u16 _len = len + 4;
    u16 sum = 0;
    for (int i = 0; i < _len; i++)
    {
        sum += buf[i];
    }

    /*填充校验和*/
    buf[_len] = sum & 0xFF;
    buf[_len + 1] = (sum >> 8) & 0xFF;

    LOG_D("tx pack(%s), len(%d)", str_type(type), len);

    return io_write(buf, len + 6, param);
}

#define STATE_HEADER 0
#define STATE_TYPE_LEN 1
#define STATE_DATA 2
#define STATE_CHECKSUM 3

void spk_packet::recv_packet_thread_ex(spk_packet_io_read_func io_read, spk_packet_callback on_rx_packet, void *param)
{
    u8 buf[SPK_PACKET_MAX_LEN + 6];

    u8 type = 0;
    u16 pack_len = 0;
    u16 sum_local = 0;
    u16 sum_remote = 0;

    while (1)
    {
        int _len = io_read(buf, SPK_PACKET_MAX_LEN + 6, 0, param);

        if (_len <= 0)
        {
            return;
        }

        for (int i = 0; i < _len; i++)
        {
            /*查找包头*/
            if (buf[i + 0] == SPK_PACKET_HEADER)
            {
                type = buf[i + 1];
                pack_len = buf[i + 2] + buf[i + 3] * 256;
                if (type >= SPK_PACKET_MIN_TYPE && type <= SPK_PACKET_MAX_TYPE && pack_len <= SPK_PACKET_MAX_LEN)
                {
                    sum_local = buf[i + 0] + buf[i + 1] + buf[i + 2] + buf[i + 3];
                }
                else
                {
                    if (pack_len > SPK_PACKET_MAX_LEN)
                    {
                        LOG_W("unexpected packet len(0x%4x),out of range", pack_len);
                    }
                    else
                    {
                        LOG_W("unexpected packet type(0x%2x)", type);
                    }
                }
                /*当前包已经接收完成?*/
                if (_len == pack_len + 6)
                {
                    for (int c = 0; c < pack_len; c++)
                    {
                        sum_local += buf[i + 4 + c];
                    }
                    sum_remote = buf[i + 4 + pack_len] + buf[i + 5 + pack_len] * 256;
                    if (sum_remote == sum_local)
                    {
                        if (on_rx_packet)
                            on_rx_packet(buf + i + 4, pack_len, type, param);
                        LOG_I("rx pack(%s), len(%d)", str_type(type), pack_len);
                        i += pack_len + 6;
                    }
                    else
                    {
                        LOG_W("unexpected packet checksum(0x%4x),expected(0x%04x)", sum_local, sum_remote);
                    }
                }
                else
                {
                    int rx_cnt = _len;

                    /*继续接收，直到接收完成*/
                    while (rx_cnt < pack_len + 6)
                    {
                        _len = io_read(buf + rx_cnt, SPK_PACKET_MAX_LEN + 6, 0, param);
                        if (_len <= 0)
                        {
                            return;
                        }
                        rx_cnt += _len;
                    }

                    for (int c = 0; c < pack_len; c++)
                    {
                        sum_local += buf[i + 4 + c];
                    }
                    sum_remote = buf[i + 4 + pack_len] + buf[i + 5 + pack_len] * 256;
                    if (sum_remote == sum_local)
                    {
                        if (on_rx_packet)
                            on_rx_packet(buf + i + 4, pack_len, type, param);
                        LOG_I("rx pack(%s), len(%d)", str_type(type), pack_len);
                        i += pack_len + 6;
                    }
                    else
                    {
                        LOG_W("unexpected packet checksum(0x%4x),expected(0x%04x)", sum_local, sum_remote);
                    }
                }
            }
        }
    }
}

void spk_packet::recv_packet_thread(spk_packet_io_read_func io_read, spk_packet_callback on_rx_packet, void *param)
{
    u8 buf[SPK_PACKET_MAX_LEN + 6];

    u8 type = 0;
    u16 pack_len = 0;
    u16 pack_rx_cnt = 0;
    u8 state = STATE_HEADER;
    u16 sum_local = 0;
    u16 next_len = 1;
    u16 sum_remote = 0;

    u8 *p = buf;

    while (1)
    {
        int _len = io_read(p, next_len, 0, param);

        if (_len != next_len)
        {
            continue;
        }

        /*处理接收状态机*/
        switch (state)
        {
        /*接收包头*/
        case STATE_HEADER:
            sum_local = SPK_PACKET_HEADER;
            if (p[0] == SPK_PACKET_HEADER)
            {
                state = STATE_TYPE_LEN;
                next_len = 3;
                p++;
            }
            else
            {
                LOG_W("unexpected packet header(0x%2x)", p[0]);
            }
            break;
        /*接收类型/长度*/
        case STATE_TYPE_LEN:
            type = p[0];
            pack_len = p[1] + p[2] * 256;
            if (type >= SPK_PACKET_MIN_TYPE && type <= SPK_PACKET_MAX_TYPE && pack_len <= SPK_PACKET_MAX_LEN)
            {
                sum_local += p[0] + p[1] + p[2];
                state = pack_len ? STATE_DATA : STATE_CHECKSUM;
                next_len = pack_len ? pack_len : 2;
                p += 3;
            }
            else
            {
                state = STATE_HEADER;
                p = buf;
                if (pack_len > SPK_PACKET_MAX_LEN)
                {
                    LOG_W("unexpected packet len(0x%4x),out of range", pack_len);
                }
                else
                {
                    LOG_W("unexpected packet type(0x%2x)", type);
                }
            }
            break;

        case STATE_DATA:
            for (int i = 0; i < pack_len; i++)
            {
                sum_local += p[i];
            }
            p += pack_len;
            next_len = 2;
            state = STATE_CHECKSUM;
            break;

        case STATE_CHECKSUM:
            sum_remote = p[0] * 256 + p[1];
            if (sum_remote == sum_local)
            {
                if (on_rx_packet)
                    on_rx_packet(p - 2, pack_len, type, param);
                LOG_I("rx pack(%s), len(%d)", str_type(type), pack_len);
            }
            else
            {
                LOG_W("unexpected packet checksum(0x%4x),expected(0x%04x)", sum_local, sum_remote);
            }
            p = buf;
            state = STATE_HEADER;
            break;

        default:
            state = STATE_HEADER;
            break;
        }
    }
}